/*
 * @filename FbAccessDecisionManager.java
 * @author yinqi
 * @version 0.0.1
 * @date 2017年7月31日
 */
package com.bnzj.core.web.security;

import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author yinqi
 */
//@Component
public class CustomAccessDecisionManager implements AccessDecisionManager {

    // decide 方法是判定是否拥有权限的决策方法，
    // authentication(用户的权限)是CustomUserDetailsService中循环添加到 GrantedAuthority 对象中的权限信息集合.
    // object 包含客户端发起的请求的requset信息，可转换为 HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
    // configAttributes(能够访问该资源的权限)是CustomInvocationSecurityMetadataSourceService的getAttributes(Object object)这个方法返回的结果，
    // 此方法是为了判定用户请求的url 是否在权限表中，如果在权限表中，则返回给 decide 方法，用来判定用户是否有此权限。如果不在权限表中则放行。
    /* 
     * (non-Javadoc)
     * @see org.springframework.security.access.AccessDecisionManager#decide(org.springframework.security.core.Authentication, java.lang.Object, java.util.Collection)
     */
    @Override
    public void decide(Authentication authentication, Object paramObject, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        if (configAttributes == null) {
            //如果该资源未被系统控制，就放过
            return;
        }
        //为避免重复转换，先把authentication.getAuthorities()转换为List<String>
        List<String> getAuthorityList = authentication.getAuthorities().parallelStream().map(authority -> {
            return authority.getAuthority().trim();
        }).collect(Collectors.toList());
        //anyMatch：Stream中只要有一个元素符合传入的predicate，就返回true
        if(configAttributes.parallelStream().anyMatch(configAttribute -> getAuthorityList.contains(configAttribute.getAttribute().trim()))) {
            return;
        }
        throw new AccessDeniedException("权限不足");
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.security.access.AccessDecisionManager#supports(org.springframework.security.access.ConfigAttribute)
     */
    @Override
    public boolean supports(ConfigAttribute paramConfigAttribute) {
        return true;
    }
    /*
     * (non-Javadoc)
     * @see org.springframework.security.access.AccessDecisionManager#supports(java.lang.Class)
     */
    @Override
    public boolean supports(Class<?> paramClass) {
        return true;
    }
}
